package org.deltaset.meta.faces;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import javax.annotation.ManagedBean;
import javax.inject.Inject;
import org.deltaset.meta.MetaActionHandler;
import org.deltaset.meta.MetaEntry;
import org.deltaset.meta.MetaHandlerFactory;
import org.primefaces.model.LazyDataModel;
import org.springframework.context.annotation.Scope;
import org.springframework.web.context.WebApplicationContext;

/**
 *
 * @author dmakariev
 */
@ManagedBean
@Scope(value = WebApplicationContext.SCOPE_SESSION)
public class MetaCrudSession implements Serializable {

    private final Map<String, MetaEntryState> metaEntryStateMap;
    private final HistoryStack historyStack;
    private final MetaHandlerFactory metaHandlerFactory;
    private final MetaActionHandler metaActionHandler;
    

    @Inject
    public MetaCrudSession(final LazyInit lazyInit) {
        this.metaEntryStateMap = new HashMap<String, MetaEntryState>();
        this.historyStack = new HistoryStack();
        this.metaHandlerFactory = lazyInit.getMetaHandlerFactory();
        this.metaActionHandler = lazyInit.getMetaActionHandler();
    }

    
    
    

    public AttributeContext getAttributeContext() {
        return historyStack.current();
    }

    public void pushAttributeContext(final AttributeContext attributeContext) {

        final AttributeContext currentAttributeContext = historyStack.current();

        if ((null==attributeContext||attributeContext.isEmpty())&&null==currentAttributeContext) {
            return;
        }
        final String className = (null == attributeContext.getClassName()) ? currentAttributeContext.getClassName() : attributeContext.getClassName();
        final String recordId = attributeContext.getRecordId();
        final String viewName = (null == attributeContext.getViewName()) ? currentAttributeContext.getViewName() : attributeContext.getViewName();
        final AttributeContext newAttributeContext = new AttributeContext(className, viewName, recordId);

        historyStack.push(newAttributeContext);

    }

    public void previous() {
        historyStack.previous();
    }

    public boolean hasPrevious() {
        return historyStack.hasPrevious();
    }

    public Object getModel() {
        return getMetaEntryState().getModelDirect();
    }

    public void setModel(Object model, String viewName) {
        final String modelId = metaActionHandler.getModelId(model);
        final String className = (null!=model)?model.getClass().getName():null;
        final AttributeContext modelAttributeContext = new AttributeContext(className, viewName, modelId);
        pushAttributeContext(modelAttributeContext);
        getMetaEntryState().setModelDirect(model);
    }

    MetaEntryState getMetaEntryState() {
        final AttributeContext currentAttributeContext = getAttributeContext();
        if(null==currentAttributeContext){
            return null;
        }
        final String entityClassName = currentAttributeContext.getClassName();
        final String currentRecordId = currentAttributeContext.getRecordId();

        if (false == metaEntryStateMap.containsKey(entityClassName)) {
            final MetaEntry metaEntry = metaHandlerFactory.createMetaEntry(entityClassName);
            final MetaEntryState metaEntryState = new MetaEntryState(metaEntry);
            metaEntryStateMap.put(entityClassName, metaEntryState);
        }
        final MetaEntryState metaEntryState = metaEntryStateMap.get(entityClassName);
        updateModel(metaEntryState, currentRecordId);
        return metaEntryState;

    }

    private void updateModel(final MetaEntryState metaEntryState, final String requestRecordId) {
        final MetaEntry metaEntry = metaEntryState.getMetaEntry();
        final Object storedModel = metaEntryState.getModelDirect();
        final String storedRecordId = metaActionHandler.getModelId(storedModel);
        if (null != requestRecordId
                && false == requestRecordId.equals(storedRecordId)) {
            final Object currentModel = metaActionHandler.loadModel(metaEntry, requestRecordId);
            metaEntryState.setModelDirect(currentModel);
        }
    }
}
